package edu.hawaii.halealohacli.jcev.command;

import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.resource.sensordata.jaxb.SensorData;
import org.wattdepot.resource.source.jaxb.Source;

/**
 * This command prints out a timestamp, current power consumed and whether or not
 * the source is meeting its conservation goal.
 * @author Jesse Elfalan
 */
public class MonitorGoal implements Command {

  private String name;  //source name.
  private double power;  //current power being consumed.
  private double goalNum;
  private double goalResult;
  private XMLGregorianCalendar timestamp; 
  private boolean testArg; //for testing arguments.
/**
 * @see Contructor for the monitor goal class.  
 */
public MonitorGoal() { 
    // Fields are initialized using setAll.
  }
  
  /**
   * Create an object which gets the Current Power usage.
   * 
   * @param client The WattDepotClient which is being used to collect the data.
   * @param source The WattDepot Source name
   * @param ingoal the value for initialing the goal
   * @param inint the value for initializing the interval
   * @param base the value retrieved from the baseline map
   * @return A MonitorGoal Object
   * @throws Exception A generic Exception, or the NotAuthorizedException,
   * ResourceNotFoundException, BadXmlException, or MiscClientException thrown by the
   * WattDepotClient.
   */
  public MonitorGoal setAll(WattDepotClient client, String source,
         int ingoal, int inint, double base) throws Exception {
    SensorData data;
    this.name = source;
       
    double baseline = base;
    //sets the goal parsed from arguments
    int setGoal = ingoal;
    //sets the interval parsed from arguments
    int setInterval = inint;
    data = client.getLatestSensorData(source);
    
    // ensures the power is set to a nicer formatted double value. (setPower)
    DecimalFormat format = new DecimalFormat( "###0.00" );
    double powerValue = data.getPropertyAsDouble(SensorData.POWER_CONSUMED) / 1000;
    double returnValue = new Double(format.format(powerValue)).doubleValue();
    this.power =  returnValue;
    
    
    this.goalResult = calcGoal(baseline, setGoal, setInterval);
    
    
    // (set Time)
    this.timestamp = data.getTimestamp();
    return this;
  }
  
  /**
   * Verifies the arguments, executes the command, and prints the results to the screen.
   * 
   * @param args Space delimited string of arguments (i.e. "arg1 arg2 arg3").
   * @param client The WattDepot client that will be performing the queries.
   * @param bsmap the map created by the baseline command
   * @throws Exception If an exception was thrown by the command (i.e. bad arguments) or any of its
   * function calls.
   */
  
  //@Override
  public void executeMG(String args, WattDepotClient client, Map<String, Double> bsmap )
  throws Exception {
   Map <String, Double> localMap = bsmap;
   String[] splitArgs = new String [3]; 
   String name = "";
   double bs = 0;
   int goal = 0;
   int interval = 0;
   
   if (args.contains(" ")) { 
     System.out.println("Splitting args...");      
     splitArgs = args.split("[ ]");
  
     try {
       System.out.println("splitArgs[0]:" + splitArgs[0]);
       System.out.println("splitArgs[1]:" + splitArgs[1]);
       System.out.println("splitArgs[2]:" + splitArgs[2]);
       
     }
     catch (Exception e) {
     System.err.println("Error: problem with splitting arguments, incorrect input");
     }
     
   }
   else {
     System.out.println("Bad input, must contain spaces between arguments.");
   }
      
        List<Source> sources = client.getSources();
        boolean match = false;
        // Checks if first argument matches a source name. Throw exception if no matches.
        for (Source source : sources) {
          if (splitArgs[0].equals(source.getName())) {
            match = true;
            name = splitArgs[0];
          }
        }
        if (!match) {
          this.testArg = false;
          throw new Exception ("Error: Source \"" + splitArgs[0] + "\" does not exist.");
        }
        
        try {
          if (splitArgs[1] == null) {
            throw new Exception ("Error: An Integer was not entered for the goal input.");       
          }
          else {
           goal = Integer.parseInt(splitArgs[1]);
          }
         }
         catch (Exception e) {
          System.err.println("Error: An Integer was not entered for the goal input"); 
          return;
         }
      
         try {
            interval = Integer.parseInt(splitArgs[2]);
          }
          catch (Exception e) {
           System.err.println ("Error: An Integer was not entered for the interval input"); 
           return; 
          }
         
        //test for valid inputs
         if (interval < 0) {
           this.testArg = false;
           throw new Exception ("Error: interval entered must be an integer greater than 0.");
           }
         if ((goal < 1) || (goal > 99)) {
           this.testArg = false;
           throw new Exception("Error: goal entered must be an integer between 1 and 99.");
           }
         
         if (localMap == null) {
           throw new Exception("Error: The baseline command has not been executed. There are" +
            "no baselines set for the sources.");
         }
       
        else {
        this.testArg = true;
        
        try {
        bs = getBaseLine(localMap, name);
        }
        catch (Exception e) {
          System.err.println("Error: could not retrieve the baseline " +
                             "value with given source name.");
        }
        
        setAll (client, name, goal, interval, bs);
        System.out.println(this.toString());
           
  }

}
    
   /**
   * gets baseline from map.
   * @param map the baseline map
   * @param name the name of the source
   * @return the baseline value for the given source name
   */
  public double getBaseLine ( Map<String,Double> map, String name) {
     return map.get(name);
    }
  
  
  /**
   * calculates the goal.
   * @param base the baseline value
   * @param setG the goal value to include in calculation
   * @param setI the interval value to include in calculation
   * @return power that tower should be at to reach goal
   */
  public double calcGoal (double base, double setG, double setI) {
    double percentage = setG * .01;
    goalNum = base * percentage;
       
    return this.goalNum;
  }
  
  
  
  /**
   * gets the name of the source.
   * @return name of source
   */
  public String getName() {
    return this.name;
  }
  
  /**
   * Returns power value.
   * @return latest read power
   */
  public double getPowerReading() {
    return this.power;
  }
  
  /**
   * Returns the timestamp.
   * @return Current timestamp
   */
  public XMLGregorianCalendar getTimeStamp() {
    return this.timestamp;
  }
  
  /**
   * Tells JUnit if there was an error with arguments.
   * @return argument passed (true) or failed (false)
   */
  public boolean testArgs() {
    return testArg;
  }
  
  /**
   * Returns readable output to the user.
   * @return output that can be read by user.
   */
  @Override
  public String toString() {
    return this.name + "'s power as of " + this.timestamp.getYear() + "-" 
          + this.timestamp.getMonth() + "-" + this.timestamp.getDay() + " "
          + this.timestamp.getHour() + ":" + this.timestamp.getMinute() + ":"
          + this.timestamp.getSecond() + " was " + this.power + "kW"
          + "\n"
          + this.name + " must reduce its power usage to " + this.goalNum 
          + " in order to reach its conservation goal of a %" + this.goalResult 
          + " reduction.";
  }
  
  /**
   * Returns the string to be printed by the help command. Format:
   * "command-name [args1] [args2] .... \nDescription"
   * 
   * @return The string to be printed by the help command.
   */
  @Override
  public String getHelpString() {
    return "monitor-goal [tower | lounge] goal interval\n"
        + "Returns the current power in kW for the associated tower or lounge along " +
        "with the requirements to meet the set baseline goal.";
  }
  
 /**
  * the original override for execute method.
  * @param args string arguments
  * @param client wattdepotclient
  * @throws Exception generic exception
  * 
  */
  @Override
  public void execute(String args, WattDepotClient client) throws Exception {
    System.out.println("This shouldn't be reached.");
    
  }
}
